package com.anti.modular.sys.org.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.anti.commom.constant.SymbolConstant;
import com.anti.commom.core.exception.BusinessException;
import com.anti.commom.core.exception.enums.PermissionExceptionEnum;
import com.anti.commom.enums.CommonStatusEnum;
import com.anti.commom.pojo.node.AntdBaseTreeNode;
import com.anti.core.context.login.LoginContextHolder;
import com.anti.core.enums.DataScopeTypeEnum;
import com.anti.jdbc.DBUtils;
import com.anti.jdbc.support.page.PageParam;
import com.anti.jdbc.support.page.PageResult;
import com.anti.modular.sys.auth.factory.TreeBuildFactory;
import com.anti.modular.sys.emp.service.SysEmpExtOrgPosService;
import com.anti.modular.sys.emp.service.SysEmpService;
import com.anti.modular.sys.org.dao.SysOrgDao;
import com.anti.modular.sys.org.entity.SysOrg;
import com.anti.modular.sys.org.param.SysOrgParam;
import com.anti.modular.sys.org.service.SysOrgService;
import com.anti.modular.sys.role.service.SysRoleDataScopeService;
import com.anti.modular.sys.user.service.SysUserDataScopeService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @Description TODO
 * @Author anTi
 * @Date 2021-3-11
 */
@Service
public class SysOrgServiceImpl implements SysOrgService {
    @Resource
    DBUtils dbUtils;
    @Resource
    SysOrgDao sysOrgDao;
    @Resource
    SysEmpService sysEmpService;
    @Resource
    SysEmpExtOrgPosService sysEmpExtOrgPosService;
    @Resource
    SysUserDataScopeService sysUserDataScopeService;
    @Resource
    SysRoleDataScopeService sysRoleDataScopeService;
    @Override
    public PageResult page(PageParam pageParam, SysOrgParam sysOrgParam) {
        StringBuilder sb=new StringBuilder("select * from sys_org where status=0 ");
        Map<String,Object> params=CollectionUtil.newHashMap();
        if (ObjectUtil.isNotNull(sysOrgParam)) {
            // 根据机构名称模糊查询
            if (ObjectUtil.isNotEmpty(sysOrgParam.getName())) {
                sb.append(" and name like:name ");
                params.put("name","%"+sysOrgParam.getName()+"%");
            }
            // 根据机构id查询
            if (ObjectUtil.isNotEmpty(sysOrgParam.getId())) {
                sb.append(" and id = :id ");
                params.put("id",sysOrgParam.getId());
            }
            // 根据父机构id查询
            if (ObjectUtil.isNotEmpty(sysOrgParam.getPid())) {
                sb.append(" and id = :id or pids like :pids ");
                params.put("id",sysOrgParam.getPid());
                params.put("pids","%"+sysOrgParam.getPid()+"%");
            }
        }
        boolean superAdmin = LoginContextHolder.me().isSuperAdmin();
        // 如果是超级管理员则获取所有组织机构，否则只获取其数据范围的机构数据
        if (!superAdmin) {
            List<Long> dataScope = sysOrgParam.getDataScope();
            if (ObjectUtil.isEmpty(dataScope)) {
                return new PageResult();
            } else {
                Set<Long> dataScopeSet = CollectionUtil.newHashSet(dataScope);
                dataScope.forEach(orgId -> {
                    //此处获取所有的上级节点，放入set，用于构造完整树
                    List<Long> parentAndChildIdListWithSelf = this.getParentIdListById(orgId);
                    dataScopeSet.addAll(parentAndChildIdListWithSelf);
                });
                sb.append(" and id in (:ids) ");
                params.put("ids",dataScopeSet);
            }
        }
        sb.append(" order by sort asc ");
        PageResult result = dbUtils.query(pageParam, sb.toString(), params);
        return result;
    }


    @Override
    public List<SysOrg> list(SysOrgParam sysOrgParam) {
        StringBuilder sb=new StringBuilder("select * from sys_org where status=0 ");
        Map<String,Object> params=CollectionUtil.newHashMap();
        if (ObjectUtil.isNotNull(sysOrgParam)) {
            //根据父机构id查询
            if (ObjectUtil.isNotEmpty(sysOrgParam.getPid())) {
                sb.append(" and pid = :pid ");
                params.put("pid",sysOrgParam.getPid());
            }
        }
        //如果是超级管理员则获取所有组织机构，否则只获取其数据范围的机构数据
        boolean superAdmin = LoginContextHolder.me().isSuperAdmin();
        if (!superAdmin) {
            List<Long> dataScope = sysOrgParam.getDataScope();
            if (ObjectUtil.isEmpty(dataScope)) {
                return CollectionUtil.newArrayList();
            } else {
                Set<Long> dataScopeSet = CollectionUtil.newHashSet(dataScope);
                dataScope.forEach(orgId -> {
                    //此处获取所有的上级节点，放入set，用于构造完整树
                    List<Long> parentAndChildIdListWithSelf = this.getParentIdListById(orgId);
                    dataScopeSet.addAll(parentAndChildIdListWithSelf);
                });
                sb.append(" and id in (:ids) ");
                params.put("ids",dataScopeSet);
            }
        }
        sb.append(" order by sort asc ");
        List<SysOrg> sysOrgs = dbUtils.query(sb.toString(), SysOrg.class, params);
        return sysOrgs;
    }


    @Override
    public void add(SysOrgParam sysOrgParam) {
        //校验参数，检查是否存在相同的名称和编码
        checkParam(sysOrgParam, false);
        //获取父id
        Long pid = sysOrgParam.getPid();
        boolean superAdmin = LoginContextHolder.me().isSuperAdmin();
        //如果登录用户不是超级管理员
        if (!superAdmin) {
            //如果新增的机构父id不是0，则进行数据权限校验
            if (!pid.equals(0L)) {
                List<Long> dataScope = sysOrgParam.getDataScope();
                //数据范围为空
                if (ObjectUtil.isEmpty(dataScope)) {
                    throw new BusinessException(0,"没有权限操作该数据，请联系管理员");
                } else if (!dataScope.contains(pid)) {
                    //所添加的组织机构的父机构不在自己的数据范围内
                    throw new BusinessException(0,"没有权限操作该数据，请联系管理员");
                }
            } else {
                //如果新增的机构父id是0，则根本没权限，只有超级管理员能添加父id为0的节点
                throw new BusinessException(0,"没有权限操作该数据，请联系管理员");
            }
        }

        SysOrg sysOrg = new SysOrg();
        BeanUtil.copyProperties(sysOrgParam, sysOrg);
        this.fillPids(sysOrg);
        sysOrg.setStatus(CommonStatusEnum.ENABLE.getCode());
        sysOrg.setCreateTime(new Date());
        sysOrg.setCreateUser(LoginContextHolder.me().getSysLoginUserId());
        sysOrgDao.save(sysOrg);
    }


    @Override
    public void delete(SysOrgParam sysOrgParam) {
        SysOrg sysOrg = this.querySysOrg(sysOrgParam);
        Long id = sysOrg.getId();
        boolean superAdmin = LoginContextHolder.me().isSuperAdmin();
        if (!superAdmin) {
            List<Long> dataScope = sysOrgParam.getDataScope();
            //数据范围为空
            if (ObjectUtil.isEmpty(dataScope)) {
                throw new BusinessException(PermissionExceptionEnum.NO_PERMISSION_OPERATE);
            } else if (!dataScope.contains(id)) {
                //所操作的数据不在自己的数据范围内
                throw new BusinessException(PermissionExceptionEnum.NO_PERMISSION_OPERATE);
            }
        }
        // 该机构下有员工，则不能删
        boolean hasOrgEmp = sysEmpService.hasOrgEmp(id);
        if (hasOrgEmp) {
            throw new BusinessException(0,"该机构下有员工，无法删除");
        }

        // 该附属机构下若有员工，则不能删除
        boolean hasExtOrgEmp = sysEmpExtOrgPosService.hasExtOrgEmp(id);
        if (hasExtOrgEmp) {
            throw new BusinessException(0,"该机构下有员工，无法删除");
        }

        // 级联删除子节点
        List<Long> childIdList = this.getChildIdListById(id);
        childIdList.add(id);

        sysOrgDao.deleteAllChild(childIdList);

        // 级联删除该机构及子机构对应的角色-数据范围关联信息
        sysRoleDataScopeService.deleteRoleDataScopeListByOrgIdList(childIdList);

        // 级联删除该机构子机构对应的用户-数据范围关联信息
        sysUserDataScopeService.deleteUserDataScopeListByOrgIdList(childIdList);
    }


    @Override
    public void edit(SysOrgParam sysOrgParam) {
        SysOrg sysOrg = this.querySysOrg(sysOrgParam);
        Long id = sysOrg.getId();

        // 检测此人数据范围能不能操作这个公司
        boolean superAdmin = LoginContextHolder.me().isSuperAdmin();
        if (!superAdmin) {
            List<Long> dataScope = sysOrgParam.getDataScope();
            //数据范围为空
            if (ObjectUtil.isEmpty(dataScope)) {
                throw new BusinessException(PermissionExceptionEnum.NO_PERMISSION_OPERATE);
            }
            //数据范围中不包含本公司
            else if (!dataScope.contains(id)) {
                throw new BusinessException(PermissionExceptionEnum.NO_PERMISSION_OPERATE);
            }
        }

        //校验参数，检查是否存在相同的名称和编码
        checkParam(sysOrgParam, true);

        //如果名称有变化，则修改对应员工的机构相关信息
        if (!sysOrg.getName().equals(sysOrgParam.getName())) {
            sysEmpService.updateEmpOrgInfo(sysOrg.getId(), sysOrg.getName());
        }

        BeanUtil.copyProperties(sysOrgParam, sysOrg);
        this.fillPids(sysOrg);
        //不能修改状态，用修改状态接口修改状态
        sysOrg.setStatus(null);
        sysOrg.setUpdateTime(new Date());
        sysOrg.setUpdateUser(LoginContextHolder.me().getSysLoginUserId());
        sysOrgDao.update(sysOrg);
    }


    @Override
    public SysOrg detail(SysOrgParam sysOrgParam) {
        SysOrg sysOrg = querySysOrg(sysOrgParam);
        return sysOrg;
    }


    @Override
    public List<AntdBaseTreeNode> tree(SysOrgParam sysOrgParam) {
        List<AntdBaseTreeNode> treeNodeList = CollectionUtil.newArrayList();
        StringBuilder sb=new StringBuilder("select * from sys_org where status=0 ");
        HashMap<String, Object> params = CollectionUtil.newHashMap();
        // 如果是超级管理员则获取所有组织机构，否则只获取其数据范围的机构数据
        boolean superAdmin = LoginContextHolder.me().isSuperAdmin();
        if (!superAdmin) {
            List<Long> dataScope = sysOrgParam.getDataScope();
            if (ObjectUtil.isEmpty(dataScope)) {
                return treeNodeList;
            } else {
                Set<Long> dataScopeSet = CollectionUtil.newHashSet(dataScope);
                dataScope.forEach(orgId -> {
                    //此处获取所有的上级节点，放入set，用于构造完整树
                    List<Long> parentAndChildIdListWithSelf = this.getParentIdListById(orgId);
                    dataScopeSet.addAll(parentAndChildIdListWithSelf);
                });
                sb.append(" and id in (:ids) ");
                params.put("ids",dataScopeSet);
            }
        }

        //根据排序升序排列，序号越小越在前
        sb.append(" order by sort asc ");
        List<SysOrg> list = dbUtils.query(sb.toString(), SysOrg.class, params);
        list.forEach(sysOrg -> {
            AntdBaseTreeNode orgTreeNode = new AntdBaseTreeNode();
            orgTreeNode.setId(sysOrg.getId());
            orgTreeNode.setParentId(sysOrg.getPid());
            orgTreeNode.setTitle(sysOrg.getName());
            orgTreeNode.setValue(String.valueOf(sysOrg.getId()));
            orgTreeNode.setWeight(sysOrg.getSort());
            treeNodeList.add(orgTreeNode);
        });

        return new TreeBuildFactory<AntdBaseTreeNode>().doTreeBuild(treeNodeList);
    }

    @Override
    public List<Long> getDataScopeListByDataScopeType(Integer dataScopeType, Long orgId) {
        List<Long> resultList = CollectionUtil.newArrayList();
        if (ObjectUtil.isEmpty(orgId)) {
            return CollectionUtil.newArrayList();
        }
        // 如果是范围类型是全部数据，则获取当前系统所有的组织架构id
        if (DataScopeTypeEnum.ALL.getCode().equals(dataScopeType)) {
            resultList = this.getOrgIdAll();
        }
        // 如果范围类型是本部门及以下部门，则查询本节点和子节点集合，包含本节点
        else if (DataScopeTypeEnum.DEPT_WITH_CHILD.getCode().equals(dataScopeType)) {
            resultList = this.getChildIdListWithSelfById(orgId);
        }
        // 如果数据范围是本部门，不含子节点，则直接返回本部门
        else if (DataScopeTypeEnum.DEPT.getCode().equals(dataScopeType)) {
            resultList.add(orgId);
        }

        return resultList;
    }

    /**
     * 根据条件获取组织机构id集合
     */
    private List<Long> getOrgIdAll() {
        List<Long> resultList = dbUtils.query("select id from sys_org where status = 0", Long.class);
        return resultList;
    }

    /**
     * 根据节点id获取所有子节点id集合，包含自己
     */
    private List<Long> getChildIdListWithSelfById(Long id) {
        List<Long> childIdListById = this.getChildIdListById(id);
        List<Long> resultList = CollectionUtil.newArrayList(childIdListById);
        resultList.add(id);
        return resultList;
    }

    /**
     * 根据节点id获取所有子节点id集合
     */
    private List<Long> getChildIdListById(Long id) {
        List<Long> childIdList = CollectionUtil.newArrayList();
        ArrayList<Object> param = CollectionUtil.newArrayList();
        String sql="select id from sys_org where status=0 and pids like ? ";
        param.add("%"+SymbolConstant.LEFT_SQUARE_BRACKETS + id + SymbolConstant.RIGHT_SQUARE_BRACKETS+"%");
        List<Long> list = dbUtils.query(sql, Long.class, param.toArray());
        list.forEach(orgId -> childIdList.add(orgId));
        return childIdList;
    }
    /**
     * 获取系统组织机构
     */
    private SysOrg querySysOrg(SysOrgParam sysOrgParam) {
        SysOrg sysOrg =dbUtils.getFirst("select * from sys_org where id =? ",SysOrg.class,sysOrgParam.getId());
        if (ObjectUtil.isNull(sysOrg)) {
            throw new BusinessException(0,"机构不存在");
        }
        return sysOrg;
    }
    /**
     * 根据节点id获取所有父节点id集合，不包含自己
     */
    private List<Long> getParentIdListById(Long id) {
        List<Long> resultList = CollectionUtil.newArrayList();
        SysOrg sysOrg =dbUtils.getFirst("select * from sys_org where id =? ",SysOrg.class,id);
        String pids = sysOrg.getPids();
        String pidsWithRightSymbol = StrUtil.removeAll(pids, SymbolConstant.LEFT_SQUARE_BRACKETS);
        String pidsNormal = StrUtil.removeAll(pidsWithRightSymbol, SymbolConstant.RIGHT_SQUARE_BRACKETS);
        String[] pidsNormalArr = pidsNormal.split(SymbolConstant.COMMA);
        for (String pid : pidsNormalArr) {
            resultList.add(Convert.toLong(pid));
        }
        return resultList;
    }

    /**
     * 校验参数，检查是否存在相同的名称和编码
     */
    private void checkParam(SysOrgParam sysOrgParam, boolean b) {
        Long id = sysOrgParam.getId();
        String name = sysOrgParam.getName();
        String code = sysOrgParam.getCode();
        Long pid = sysOrgParam.getPid();

        //如果父id不是根节点
        if (!pid.equals(0L)) {
            SysOrg sysOrg =dbUtils.getFirst("select * from sys_org where id =? ",SysOrg.class,pid);
            if (ObjectUtil.isNull(sysOrg)) {
                throw new BusinessException(0,"机构不存在");
            }
        }
        // 如果是编辑，父id和自己的id不能一致
        if (b) {
            if (sysOrgParam.getId().equals(sysOrgParam.getPid())) {
                throw new BusinessException(0,"父节点不能和本节点一致，请重新选择父节点");
            }
        }
        StringBuilder sb=new StringBuilder("select count(*) from sys_org where status=0 and name =? and code =? ");
        List<Object> params=CollectionUtil.newArrayList();
        params.add(name);
        params.add(code);
        if (b) {
            sb.append(" and id <> ? ");
            params.add(id);

        }
        int countByName = dbUtils.getFirst(sb.toString(),Integer.class,params.toArray());
        if (countByName >= 1) {
            throw new BusinessException(0,"组织机构名称或编码重复，请检查name或code参数");
        }
    }

    /**
     * 填充父ids
     */
    private void fillPids(SysOrg sysOrg) {
        if (sysOrg.getPid().equals(0L)) {
            sysOrg.setPids(SymbolConstant.LEFT_SQUARE_BRACKETS +
                    0 +
                    SymbolConstant.RIGHT_SQUARE_BRACKETS +
                    SymbolConstant.COMMA);
        } else {
            //获取父组织机构
            SysOrg pSysOrg =dbUtils.getFirst("select * from sys_org where id =? ",SysOrg.class,sysOrg.getPid());
            sysOrg.setPids(pSysOrg.getPids() +
                    SymbolConstant.LEFT_SQUARE_BRACKETS + pSysOrg.getId() +
                    SymbolConstant.RIGHT_SQUARE_BRACKETS +
                    SymbolConstant.COMMA);
        }
    }
}
